In [ ]:
%%HTML
<style>
.container { width:100% }
</style>
The module Set implements sets as
AVL trees.
The API provided by Set offers the following functions and methods:
Set() creates an empty set.S.isEmpty() checks whether the set Sis empty.S.member(x) checks whether x is an element of the set S.S.insert(x) inserts x into the set S.
This does not return a new set but rather modifies the set S.S.delete(x) deletes x from the set S.
This does not return a new set but rather modifies the set S.S.pop() returns the smallest element of the set S.
Furthermore, this element is removed from S.Since sets are implemented as ordered binary trees, the elements of a set need to be comparable, i.e. if x and y are inserted into a set, then the expression x < y must return a Boolean value and < has to define a linear order. Therefore, sets must not be inhomogeneous, i.e. the sets must not contain elements of different types.
In this notebook, the module Set is used to implement a priority queue that supports the removal of elements.
In [ ]:
import Set
The function search takes three arguments to solve a search problem:
start is the start state of the search problem,goalis the goal state, andnext_states is a function with signature $\texttt{next_states}:Q \rightarrow 2^Q$, where $Q$ is the set of states.
For every state $s \in Q$, $\texttt{next_states}(s)$ is the set of states that can be reached from $s$ in one step.heuristic is a function that takes two states as arguments. It returns an estimate of the
length of the shortest path between these states.If successful, search returns a path from start to goal that is a solution of the search problem
$$ \langle Q, \texttt{next_states}, \texttt{start}, \texttt{goal} \rangle. $$
For A$^*$ search to find optimal paths it is required that heuristicis consistent, which requires the following properties:
The function search implements A$^*$ search. It maintains the following variables:
PathDict is a dictionary. For every state s such that PathDict[s] is defined, PathDict[s] is a path from source to s.Distance is a dictionary. For every state s such that Distance[s] is defined, Distance[s] is the length of the path PathDict[s]. Furthermore, it can be shown that this path is the shortest path connecting source with s. If Distance[s] is defined, then we say that s has been visited.Estimate is a dictionary. For every state s such that Estimate[s] is defined, Estimate[s] is the expected length of a path from start to goalthat leads via s.Frontier is an ordered set of pairs of the form $(d, s)$ where $s$ is a state and $d = \texttt{Estimate}[s]$. This set is used as a priority queue.Explored is the set of all states that have been explored. A state $s$ is explored if all of its neighbours have been visited.
In [ ]:
def search(start, goal, next_states, heuristic):
PathDict = { start: [start] }
Distance = { start: 0 }
estGoal = heuristic(start, goal)
Estimate = { start: estGoal }
Frontier = Set.Set()
Frontier.insert( (estGoal, start) )
Explored = set()
while not Frontier.isEmpty():
_, state = Frontier.pop()
if state == goal:
return PathDict[state]
stateDist = Distance[state]
for ns in next_states(state):
oldEstimate = Estimate.get(ns, None)
newEstimate = stateDist + 1 + heuristic(ns, goal)
if oldEstimate == None or newEstimate < oldEstimate:
Distance[ns] = stateDist + 1
Estimate[ns] = newEstimate
PathDict[ns] = PathDict[state] + [ns]
Frontier.insert( (newEstimate, ns) )
if oldEstimate != None:
Frontier.delete( (oldEstimate, ns) )
Explored.add(state)
Lets draw the start state and animate the solution that has been found.
In [ ]:
%run Sliding-Puzzle.ipynb
In [ ]:
%%time
Path = search(start, goal, next_states, manhattan)
print(len(Path)-1)
In [ ]:
animation(Path)
In [ ]: